package com.asa.mvvm_aop_frame.basic

import android.Manifest
import android.app.Application
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.os.Environment
import androidx.core.content.ContextCompat
import com.asa.mvvm_aop_frame.basic.ext.TYPE_DOCUMENT
import com.asa.mvvm_aop_frame.basic.ext.createDir
import java.io.*
import java.lang.Exception
import java.lang.reflect.Method
import java.text.SimpleDateFormat

/**
 * create By：anderson
 * on 2022/4/27
 * 异常捕获类
 * 需要在Application中实现[com.oplus.studycenter.common.base.BaseContract.IApplication.crashOpera]
 * 如果不重写该方法，框架内部默认将异常导入本地，本地路径为：
 *  --版本大于安卓Q：Android/data/data/packageName/document/crash/crash_test.trace
 *  --版本小于安卓Q：sd/packageName/document/crash/crash_test.trace
 * @property context Context?
 * @property defaultCrashHandler UncaughtExceptionHandler?
 */
class CrashHandler private constructor():Thread.UncaughtExceptionHandler{

    private var context:Context?=null
    private var defaultUncaughtExceptionHandler: Thread.UncaughtExceptionHandler?=null

    companion object{
        val instance : CrashHandler by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED){
            CrashHandler()
        }
    }

    fun init(context:Context){
        this.context = context
        defaultUncaughtExceptionHandler  = Thread.getDefaultUncaughtExceptionHandler()
        Thread.setDefaultUncaughtExceptionHandler(this)
    }

    override fun uncaughtException(t: Thread, e: Throwable) {
        try {
            dumpExceptionToSDCard(e)

            var application:Application ?= null
            var declaredMethod : Method ?= null
            if (context is Application){
                application = context as Application
                declaredMethod =
                    application.javaClass.getDeclaredMethod("crashOpera",Throwable::class.java)
            }
            declaredMethod?.invoke(application,e)
        }catch (ex:Exception){
            e.printStackTrace()
        }
        //打印到控制台
        e.printStackTrace()
        //如果系统提供了默认的异常处理器，则交给系统去结束程序，否则就由自己结束自己
        if (defaultUncaughtExceptionHandler != null) {
            defaultUncaughtExceptionHandler!!.uncaughtException(t, e)
        }
    }

    private fun dumpExceptionToSDCard(ex: Throwable) {
        context?.also {
            if (ContextCompat.checkSelfPermission(it,Manifest.permission.WRITE_EXTERNAL_STORAGE) !=  PackageManager.PERMISSION_GRANTED){
                return
            }
            //如果sd卡不存在或者是不能使用
            if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
                return
            }
            val current = System.currentTimeMillis()
            val time:String = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(current)
            val file =File(it.createDir(TYPE_DOCUMENT,"crash"), "crash_$time.track")
            val pw = PrintWriter(BufferedWriter(FileWriter(file)))
            pw.println(time)
            pw.println()
            ex.printStackTrace(pw)
            pw.close()
        }
    }

    private fun dumpPhoneInfo(pw: PrintWriter) {
        context?.also {
            val pm = it.packageManager
            val pi = pm.getPackageInfo(
                it.packageName,
                PackageManager.GET_ACTIVITIES
            )
            pw.print("App Version: ")
            pw.print(pi.versionName)
            pw.print('_')
            pw.println(pi.versionCode)
            //Android版本号
            pw.print("OS Version: ")
            pw.print(Build.VERSION.RELEASE)
            pw.print("_")
            pw.println(Build.VERSION.SDK_INT)
            //手机制造商
            pw.print("Vendor: ")
            pw.println(Build.MANUFACTURER)
            //手机型号
            pw.print("Model: ")
            pw.println(Build.MODEL)
            //CPU架构
            pw.print("CPU ABI: ")
            pw.println(Build.CPU_ABI)
        }
    }

}